package com.demomaster.quickcompat.util

import android.Manifest
import android.annotation.TargetApi
import android.bluetooth.BluetoothAdapter
import android.content.Context
import android.content.pm.PackageManager
import android.hardware.Sensor
import android.hardware.SensorManager
import android.net.wifi.WifiManager
import android.os.Build
import android.provider.Settings
import android.telephony.TelephonyManager
import android.text.TextUtils
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.annotation.RequiresPermission
import java.io.BufferedReader
import java.io.File
import java.io.IOException
import java.io.InputStreamReader
import java.nio.charset.StandardCharsets
import java.security.MessageDigest
import java.security.NoSuchAlgorithmException
import java.util.Arrays
import java.util.Locale

class DeviceUtil {
    companion object {
        private const val TAG = "DeviceUtil"

        /**
         * Pseudo-Unique ID, 这个在任何Android手机中都有效
         * 有一些特殊的情况，一些如平板电脑的设置没有通话功能，或者你不愿加入READ_PHONE_STATE许可。而你仍然想获得唯
         * 一序列号之类的东西。这时你可以通过取出ROM版本、制造商、CPU型号、以及其他硬件信息来实现这一点。这样计算出
         * 来的ID不是唯一的（因为如果两个手机应用了同样的硬件以及Rom 镜像）。但应当明白的是，出现类似情况的可能性基
         * 本可以忽略。大多数的Build成员都是字符串形式的，我们只取他们的长度信息。我们取到13个数字，并在前面加上“35
         * ”。这样这个ID看起来就和15位IMEI一样了。
         *
         * @return PesudoUniqueID
         */
        @JvmStatic
        fun getPesudoUniqueID(): String {
            val m_szDevIDShort = //we make this look like a valid IMEI
                "35" + Build.BOARD.length % 10 + Build.BRAND.length % 10 + Build.CPU_ABI.length % 10 + Build.DEVICE.length % 10 + Build.DISPLAY.length % 10 + Build.HOST.length % 10 + Build.ID.length % 10 + Build.MANUFACTURER.length % 10 + Build.MODEL.length % 10 + Build.PRODUCT.length % 10 + Build.TAGS.length % 10 + Build.TYPE.length % 10 + Build.USER.length % 10 //13 digits
            return m_szDevIDShort
        }

        /**
         * The Android ID
         * 通常被认为不可信，因为它有时为null。开发文档中说明了：这个ID会改变如果进行了出厂设置。并且，如果某个
         * Andorid手机被Root过的话，这个ID也可以被任意改变。无需任何许可。
         *
         * @return AndroidID
         */
        @JvmStatic
        fun getAndroidID(mContext: Context): String {
            val m_szAndroidID = Settings.Secure.getString(
                mContext.contentResolver,
                Settings.Secure.ANDROID_ID
            )
            return m_szAndroidID
        }

        /**
         * The WLAN MAC Address string
         * 是另一个唯一ID。但是你需要为你的工程加入android.permission.ACCESS_WIFI_STATE 权限，否则这个地址会为
         * null。Returns: 00:11:22:33:44:55 (这不是一个真实的地址。而且这个地址能轻易地被伪造。).WLan不必打开，
         * 就可读取些值。
         *
         * @return m_szWLANMAC
         */
        @JvmStatic
        fun getWLANMACAddress(mContext: Context): String {
            val wm = mContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
            val m_szWLANMAC = wm.connectionInfo.macAddress
            return m_szWLANMAC
        }

        /**
         * 只在有蓝牙的设备上运行。并且要加入android.permission.BLUETOOTH 权限.Returns: 43:25:78:50:93:38 .
         * 蓝牙没有必要打开，也能读取。
         *
         * @return m_szBTMAC
         */
        @JvmStatic
        fun getBTMACAddress(mContext: Context?): String? {
            var m_BluetoothAdapter: BluetoothAdapter? = null // Local Bluetooth adapter
            m_BluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
            if (m_BluetoothAdapter == null) {
                return null
            }
            val m_szBTMAC = m_BluetoothAdapter.address
            return m_szBTMAC
        }

        /**
         * Combined Device ID
         * 综上所述，我们一共有五种方式取得设备的唯一标识。它们中的一些可能会返回null，或者由于硬件缺失、权限问题等
         * 获取失败。但你总能获得至少一个能用。所以，最好的方法就是通过拼接，或者拼接后的计算出的MD5值来产生一个结果。
         * 通过算法，可产生32位的16进制数据:9DDDF85AFF0A87974CE4541BD94D5F55
         *
         * @return
         */
        @JvmStatic
        fun getUniqueID(mContext: Context): String {
//        String m_szLongID = getIMEI() + getPesudoUniqueID()
//                + getAndroidID() + getWLANMACAddress() + getBTMACAddress();
            val m_szLongID =
                getPesudoUniqueID() + getWLANMACAddress(mContext) + getBTMACAddress(mContext)
            // compute md5
            var m: MessageDigest? = null
            try {
                m = MessageDigest.getInstance("MD5")
            } catch (e: NoSuchAlgorithmException) {
                Log.e(TAG,e.toString())
            }
            m!!.update(m_szLongID.toByteArray(), 0, m_szLongID.length)
            // get md5 bytes
            val p_md5Data = m!!.digest()
            // create a hex string
            val stringBuilder = StringBuilder()
            for (p_md5Datum in p_md5Data) {
                val b = (0xFF and p_md5Datum.toInt())
                // if it is a single digit, make sure it have 0 in front (proper padding)
                if (b <= 0xF) {
                    stringBuilder.append("0")
                }
                // add number to string
                stringBuilder.append(Integer.toHexString(b))
            } // hex string to uppercase

            return stringBuilder.toString().uppercase(Locale.getDefault())
        }

        //判断手机是否root
        @JvmStatic
        fun isRoot(): Boolean {
            val binPath = "/system/bin/su"
            val xBinPath = "/system/xbin/su"
            if (File(binPath).exists() && isCanExecute(binPath)) {
                return true
            }
            return (File(xBinPath).exists() && isCanExecute(xBinPath))
        }

        /**
         * 判断是否开启了root权限
         *
         * @return
         */
        @JvmStatic
        fun isRootSystem(): Boolean {
            //多数只要su可执行就是root成功了，但是成功后用户如果删掉了权限管理的app，就会造成第三方app无法申请root权限，此时是用户删root权限管理app造成的。
            //市场上常用的的权限管理app的包名   com.qihoo.permmgr  com.noshufou.android.su  eu.chainfire.supersu   com.kingroot.kinguser  com.kingouser.com  com.koushikdutta.superuser
            //com.dianxinos.superuser  com.lbe.security.shuame com.geohot.towelroot 。。。。。。
            return isRootSystem1() || isRootSystem2()
        }
        @JvmStatic
        private fun isRootSystem1(): Boolean {
            var f: File? = null
            val kSuSearchPaths = arrayOf(
                "/system/bin/", "/system/xbin/",
                "/system/sbin/", "/sbin/", "/vendor/bin/"
            )
            try {
                for (kSuSearchPath in kSuSearchPaths) {
                    f = File(kSuSearchPath + "su")
                    if (f != null && f.exists() && f.canExecute()) {
                        return true
                    }
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
            return false
        }
        @JvmStatic
        private fun isRootSystem2(): Boolean {
            val pros = getPath()
            var f: File? = null
            try {
                for (i in pros.indices) {
                    f = File(pros[i], "su")
                    println("f.getAbsolutePath():" + f.absolutePath)
                    if (f.exists() && f.canExecute()) {
                        return true
                    }
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
            return false
        }
        @JvmStatic
        private fun getPath(): List<String> {
            return Arrays.asList(
                *System.getenv("PATH").split(":".toRegex()).dropLastWhile { it.isEmpty() }
                    .toTypedArray())
        }
        @JvmStatic
        private fun isCanExecute(filePath: String): Boolean {
            var process: Process? = null
            try {
                process = Runtime.getRuntime().exec("ls -l $filePath")
                val `in` = BufferedReader(InputStreamReader(process.inputStream))
                val str = `in`.readLine()
                if (str != null && str.length >= 4) {
                    val flag = str[3]
                    if (flag == 's' || flag == 'x') return true
                }
            } catch (e: IOException) {
                e.message?.let { Log.e(TAG, it) }
            } finally {
                process?.destroy()
            }
            return false
        }
        @RequiresPermission("android.permission.BLUETOOTH_CONNECT")
        @JvmStatic
        fun isSimulator(context: Context): Boolean {
            return notHasBlueTooth() || BooleannotHasLightSensorManager(context) || checkIsNotRealPhone()
        }

        /**
         * 判断蓝牙是否有效来判断是否为模拟器
         *
         * @return true 为模拟器
         */
        @RequiresPermission("android.permission.BLUETOOTH_CONNECT")
        @JvmStatic
        fun notHasBlueTooth(): Boolean {
            val ba = BluetoothAdapter.getDefaultAdapter()
            if (ba == null) {
                return true
            } else {
                // 如果有蓝牙不一定是有效的。获取蓝牙名称，若为null 则默认为模拟器
                val name = ba.name
                return (TextUtils.isEmpty(name))
            }
        }

        /**
         * 判断是否存在光传感器来判断是否为模拟器
         * 部分真机也不存在温度和压力传感器。其余传感器模拟器也存在。
         *
         * @return true 为模拟器
         */
        @JvmStatic
        fun BooleannotHasLightSensorManager(context: Context): Boolean {
            val sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
            val sensor8 = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT) //光
            return (null == sensor8)
        }

        /**
         * 判断cpu是否为电脑来判断 模拟器
         *
         * @return true 为模拟器
         */
        @JvmStatic
        @RequiresApi(api = Build.VERSION_CODES.KITKAT)
        fun checkIsNotRealPhone(): Boolean {
            val cpuInfo = readCpuInfo()
            return ((cpuInfo.contains("intel") || cpuInfo.contains("amd")))
        }
        @JvmStatic
        @RequiresApi(api = Build.VERSION_CODES.KITKAT)
        fun readCpuInfo(): String {
            var result = ""
            try {
                val args = arrayOf("/system/bin/cat", "/proc/cpuinfo")
                val cmd = ProcessBuilder(*args)
                val process = cmd.start()
                val sb = StringBuilder()
                var readLine: String? = ""
                val responseReader =
                    BufferedReader(InputStreamReader(process.inputStream, StandardCharsets.UTF_8))
                while ((responseReader.readLine().also { readLine = it }) != null) {
                    sb.append(readLine)
                }
                responseReader.close()
                result = sb.toString().lowercase(Locale.getDefault())
            } catch (ex: IOException) {
                ex.printStackTrace()
            }
            return result
        }

        /**
         * 获取运营商sim卡的ICCID号
         * Manifest.permission.READ_PHONE_STATE)
         *
         * @return ICCID号
         */
        @JvmStatic
        fun getICCID(context: Context): String? {
            val tm = context
                .getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
            // 获取sim卡的ICCID号
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (context.checkSelfPermission(Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
                    return null
                }
            }
            return tm.simSerialNumber
        }
    }
}